package com.example.job;
import cn.hutool.json.JSONUtil;
import com.example.dto.Job;
import com.example.dto.JobChange;
import com.example.service.JobService;
import com.example.utils.CollUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.time.Duration;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;

/*
@description:
@ClassName SpringJobRunManager
@author chen
@create 2025-07-08 16:55
@Version 1.0
*/
@Component
public class SpringJobRunManager implements CommandLineRunner
{
    @Resource
    private ApplicationContext applicationContext;
    @Resource
    private ThreadPoolTaskScheduler threadPoolTaskScheduler;
    private static final Logger logger = LoggerFactory.getLogger(SpringJobRunManager.class);
    // 系统重正在运行中的job列表
    private Map<String, SpringJobTask> runningJobMap = new ConcurrentHashMap<>();

    @Resource
    private JobService jobService;

    /*
     * @param args
     * @==============History===============<br/>;
     * @Description //   springboot应用启动后会回调
     * @Date 2025/7/8
     */
    @Override
    public void run(String... args)
    {
        // 1.启动job
        this.startAllJob();
        // 2.监控db中job的变化(job增、删、改)，然后同步给job执行器去执行
        this.monitorDbJobChange();
    }


    private void startAllJob()
    {
        List<Job> jobList = jobService.getStartJobList();
        for (Job job : jobList)
        {
            this.startJob(job);
        }
    }



    private void monitorDbJobChange()
    {
        this.threadPoolTaskScheduler.scheduleWithFixedDelay(this::jobChangeDispose, Duration.ofSeconds(5));
    }


    private void jobChangeDispose()
    {
        try
        {
            // 从db中拿到所有job，和目前内存中正在运行的所有job对比，可得到本次新增的job、删除的job、更新的job
            JobChange jobChange = getJobChange();
            if(null != jobChange)
            {
                // 新增的job启动下
                List<Job> addJobList = jobChange.getAddJobList();
                if(addJobList.size() > 0)
                {
                    for (Job job : addJobList)
                    {
                        this.startJob(job);
                    }
                }

                // 删除的job停止下,从map中移除
                List<Job> deleteJobList = jobChange.getDeleteJobList();
                if(deleteJobList.size() > 0)
                {
                    for (Job job : deleteJobList)
                    {
                        this.deleteJob(job);
                    }
                }

                // 处理变化的job
                List<Job> updateJobList = jobChange.getUpdateJobList();
                if(updateJobList.size() > 0)
                {
                    for (Job job : updateJobList)
                    {
                        this.updateJob(job);
                    }
                }
            }
        }catch (Exception e)
        {
            logger.error(e.getMessage(), e);
            e.printStackTrace();
        }

    }


    private JobChange getJobChange()
    {
        // 新增的job
        List<Job> addJobList = new ArrayList<>();
        // 删除的job
        List<Job> deleteJobList = new ArrayList<>();
        // 更新的job
        List<Job> updateJobList = new ArrayList<>();

        List<Job> startJobList = jobService.getStartJobList();
        if(null != startJobList && startJobList.size() > 0)
        {
            // 过滤增加和修改的job
            for (Job job : startJobList)
            {
                SpringJobTask springJobTask = runningJobMap.get(job.getId());
                if(null == springJobTask)
                {
                    addJobList.add(job);
                }
                else
                {
                    if(jobIsChange(job, springJobTask.getJob()))
                    {
                        updateJobList.add(job);
                    }
                }
            }

            // 获取被删除的job，springJobTaskMap中存在的，而startJobList不存在的，则是需要从当前运行列表中停止移除的
            Set<String> startJobIdList = CollUtils.convertSet(startJobList, Job::getId);
            for (Map.Entry<String, SpringJobTask> springJobTaskEntry : runningJobMap.entrySet())
            {
                if (!startJobIdList.contains(springJobTaskEntry.getKey()))
                {
                    deleteJobList.add(springJobTaskEntry.getValue().getJob());
                }
            }
            // 返回job变更结果
            JobChange jobChange = new JobChange();
            jobChange.setAddJobList(addJobList);
            jobChange.setUpdateJobList(updateJobList);
            jobChange.setDeleteJobList(deleteJobList);
            return jobChange;
        }
        return null;
    }




    private boolean jobIsChange(Job job1, Job job2)
    {
        return !(Objects.equals(job1.getCron(), job2.getCron()) &&
                Objects.equals(job1.getBeanName(), job2.getBeanName()) &&
                Objects.equals(job1.getBeanMethod(), job2.getBeanMethod()));
    }




    /*
     * @param job
     * @==============History===============<br/>;
     * @Description //   启动job
     * @Date 2025/7/9
     */
    private void startJob(Job job)
    {
        SpringJobTask springJobTask = new SpringJobTask(job, this.applicationContext);
        CronTrigger trigger = new CronTrigger(job.getCron());
        ScheduledFuture<?> scheduledFuture = threadPoolTaskScheduler.schedule(springJobTask, trigger);
        springJobTask.setScheduledFuture(scheduledFuture);
        runningJobMap.put(job.getId(), springJobTask);
        logger.info("启动 job 成功:{}", JSONUtil.toJsonStr(job));
    }


    /*
     * @param job
     * @==============History===============<br/>;
     * @Description //   删除job
     * @Date 2025/7/9
     */
    private void deleteJob(Job job)
    {
        if (job == null) return;

        SpringJobTask springJobTask = this.runningJobMap.get(job.getId());

        if (springJobTask == null)  return;

        // 取消job的执行
        springJobTask.getScheduledFuture().cancel(false);

        // 将job从map中移除
        runningJobMap.remove(job.getId());

        logger.info("移除 job 成功:{}", JSONUtil.toJsonStr(job));
    }

    /*
     * @param
     * @param job
     * @==============History===============<br/>;
     * @Description //   更新job
     * @Date 2025/7/9
     */
    public void updateJob(Job job)
    {
        // 先删除旧的job
        this.deleteJob(job);
        // 运行新的job
        this.startJob(job);
        logger.info("更新 job 成功:{}", JSONUtil.toJsonStr(job));
    }
}
